﻿using System;
using System.Diagnostics;

using Microsoft.Xna.Framework.Graphics;

namespace HorrorsOfArkham.Game_Application_Layer
{
    public abstract class TimedXnaGame : XnaGame
    {
        #region Members

        private readonly Stopwatch _elapsedGameTimeStopwatch = new Stopwatch();
        protected readonly XnaGameTime _gameTime = new XnaGameTime();
        private readonly Stopwatch _totalGameTimeStopwatch = new Stopwatch();

        private const float OPTIMAL_DELTA_TIME = 1.0f / 60.0f * 1000;
        private const float MAX_FRAME_TIME = 15f;

        public bool Paused
        {
            get;
            private set;
        }

        #endregion

        #region Initialization

        protected TimedXnaGame(GraphicsDevice graphicsDevice, IContentManagerProvider contentManagerProvider)
            : base(graphicsDevice, contentManagerProvider)
        { 
        }

        protected override void Initialize()
        {
            _totalGameTimeStopwatch.Start();
            _elapsedGameTimeStopwatch.Start();
        }

        #endregion

        #region Running

        public void Pause()
        {
            if (!Running)
            {
                throw new InvalidOperationException("Game is not running");
            }

            Paused = true;
            _totalGameTimeStopwatch.Stop();
            _elapsedGameTimeStopwatch.Stop();
        }

        public void Unpause()
        {
            if (!Running)
            {
                throw new InvalidOperationException("Game is not running");
            }

            Paused = false;
            _totalGameTimeStopwatch.Start();
            _elapsedGameTimeStopwatch.Start();
        }

        #endregion

        #region Update

        protected override void BeforeTick()
        {
            if (Paused)
            {
                return;
            }

            TimeSpan totalGameTime = _totalGameTimeStopwatch.Elapsed;
            TimeSpan elapsedGameTime = _elapsedGameTimeStopwatch.Elapsed;

            _elapsedGameTimeStopwatch.Restart();

            _gameTime.TotalGameTime = totalGameTime;
            _gameTime.ElapsedGameTime = elapsedGameTime;
        }

        protected override void Update()
        {
            if (!Paused)
            {
                Update(_gameTime);
            }
        }

        protected virtual void Update(IXnaGameTime gameTime)
        {
            TimeSpan lastFrameTime = gameTime.ElapsedGameTime;

            float deltaTime = 0;

            if (lastFrameTime.Milliseconds > MAX_FRAME_TIME)
            {
                deltaTime = OPTIMAL_DELTA_TIME;
            }
            else
            {
                deltaTime = lastFrameTime.Milliseconds;
            }

            Console.WriteLine("Delta time: " + deltaTime);
        }

        #endregion

        #region Draw

        protected override void Draw()
        {
            Draw(_gameTime);
        }

        protected virtual void Draw(IXnaGameTime gameTime)
        { 
        }

        #endregion

        #region XnaGameTime Class

        protected class XnaGameTime : IXnaGameTime
        {
            public TimeSpan TotalGameTime
            {
                get;
                set;
            }

            public TimeSpan ElapsedGameTime
            {
                get;
                set;
            }
        }

        #endregion
    }
}
